package com.rightrule.sequence.impl;

import com.google.common.collect.Maps;
import com.rightrule.sequence.Sequence;
import com.rightrule.sequence.SequenceService;
import com.rightrule.sequence.enums.SequenceEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ThreadLocalRandom;

/**
 * @author: xry
 * @version: SequenceServiceImpl.java 2024/9/6 20:02
 */
@Slf4j
@Service
public class SequenceServiceImpl implements SequenceService, InitializingBean {

    /**
     * 流水号容器
     */
    @Resource
    private Map<String, Sequence> sequenceMap;

    private Map<SequenceEnum, Sequence> combinationSequenceMap = Maps.newHashMap();

    /**
     * 系统版本
     */
    public static final String SYSTEM_VERSION = "0";

    /**
     * 数据版本
     */
    public static final String DATA_VERSION = "1";

    /**
     * 默认00库表
     */
    public static final String DEFAULT_DB_PLACES = "00";

    /**
     * 获取短格式日期yyyymmdd
     *
     * @return
     */
    private static String shortDate() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        return sdf.format(new Date());
    }

    /**
     * 获取流水开始字符（短格式日期+10）
     *
     * @return string
     */
    private static String seqValueStart() {
        return shortDate() + "10";
    }

    /**
     * 随机两位数
     *
     * @return
     */
    private static String random2Num() {
        int randomNum = ThreadLocalRandom.current().nextInt(0, 99);
        return StringUtils.leftPad(String.valueOf(randomNum), 2, "0");
    }

    /**
     * 获取分库分表位
     * 倒数2-3位
     *
     * @param custId
     * @return
     */
    private static String getDbPlacesByCustomerId(String custId) {
        if (StringUtils.isBlank(custId)) {
            // 为空则默认00库表
            return DEFAULT_DB_PLACES;
        }
        int length = custId.length();
        return custId.substring(length - 3, length - 1);
    }

    /**
     * 日期8位 + '10' + 分库分表位（00）+ 随机位（00）+ seq（8位）
     *
     * @param sequenceEnum
     * @return string
     */
    @Override
    public String createKeyNoWithoutSharding(SequenceEnum sequenceEnum) {
        StringBuffer sb = new StringBuffer();
        return sb.append(seqValueStart())
                .append(DEFAULT_DB_PLACES)
                .append(random2Num())
                .append(getSeqNo(sequenceEnum))
                .toString();
    }

    /**
     * 日期8位 + '10' + 分库分表位（2位）+ 随机位（00）+ seq（8位）
     *
     * @param custId       客户编号，分库分表位由它产生
     * @param sequenceEnum SEQ枚举
     * @return string
     */
    @Override
    public String createKeyNo(String custId, SequenceEnum sequenceEnum) {
        StringBuffer sb = new StringBuffer();
        return sb.append(seqValueStart())
                .append(getDbPlacesByCustomerId(custId))
                .append(DEFAULT_DB_PLACES)
                .append(getSeqNo(sequenceEnum))
                .toString();
    }

    /**
     * 日期8位 + '10' + 业务事件码（8位）+ 业务扩展位（10位）+ 分库分表位（2位）+ 随机位（2位）+ seq（8位）
     *
     * @param custId       客户编号，分库分表位由它产生
     * @param eventCode    业务事件码
     * @param bizExt       业务扩展位
     * @param sequenceEnum SEQ枚举
     * @return string
     */
    @Override
    public String createBizNo(String custId, String eventCode, String bizExt, SequenceEnum sequenceEnum) {
        // 分库分表位
        String dbPlaces = getDbPlacesByCustomerId(custId);
        StringBuffer sb = new StringBuffer();
        return sb.append(seqValueStart())
                .append(eventCode)
                .append(StringUtils.leftPad(bizExt, 10, "0"))
                .append(dbPlaces)
                .toString();
    }

    /**
     * 日期8位 + DATA_VERSION（1位）+ SYSTEM_VERSION（1位）
     * + eventCode（8位，可为空）+ 业务扩展位（10位）+ 分库分表位（2位）+ 随机位（2位 + seq（8位）
     *
     * @param ipId
     * @param eventCode
     * @param bizExt
     * @param sequenceEnum
     * @return
     */
    @Override
    public String createBizIpId(String ipId, String eventCode, String bizExt, SequenceEnum sequenceEnum) {
        StringBuffer sb = new StringBuffer();
        return sb.append(shortDate())
                .append(DATA_VERSION)
                .append(SYSTEM_VERSION)
                .append(StringUtils.defaultIfBlank(eventCode, StringUtils.EMPTY))
                .append(StringUtils.leftPad(bizExt, 10, "0"))
                .append(getDbPlacesByCustomerId(ipId))
                .append(random2Num())
                .append(getSeqNo(sequenceEnum))
                .toString();
    }

    /**
     * 生成sequenceNo
     *
     * @param sequenceEnum
     * @return
     */
    private String getSeqNo(SequenceEnum sequenceEnum) {
        Sequence sequence = combinationSequenceMap.get(sequenceEnum);
        if (Objects.isNull(sequence)) {
            sequence = new DefaultSequence(sequenceEnum.name);
        }
        return String.valueOf(sequence.nextValue());
        //if (Objects.nonNull(sequence)) {
        //    return String.valueOf(sequence.nextValue());
        //}
        //return StringUtils.EMPTY;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        log.info("start init combinationSequenceMap");
        sequenceMap.forEach((k, v) -> {
            SequenceEnum sequenceEnum = SequenceEnum.fromName(k);
            if (Objects.nonNull(sequenceEnum)) {
                combinationSequenceMap.put(sequenceEnum, v);
            }
        });
        log.info("end init combinationSequenceMap");
    }
}
